package com.jstyle.jclifexd.activity;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.jstyle.jclifexd.R;
import com.jstyle.jclifexd.ble.BleManager;
import com.jstyle.jclifexd.ble.BleService;
import com.jstyle.jclifexd.model.BleData;
import com.jstyle.jclifexd.utils.ResolveData;
import com.jstyle.jclifexd.utils.RxBus;
import com.jstyle.jclifexd.utils.SchedulersTransformer;
import com.jstyle.jclifexd.utils.ScreenUtils;

import java.io.File;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;

public class SendPicActivity extends Activity {
    private static final String TAG = "SendPicActivity";

    static final byte cmdCheck = (byte) 0x96;
    static final byte cmdSend = (byte) 0x97;
    @BindView(R.id.iv_send_pic)
    ImageView ivSendPic;
    @BindView(R.id.tv_sendPic_Progress)
    TextView tvSendPicProgress;
    private byte[] binByte;
    int packageCount;
    int Count;
    int sendTotalPackage;//块发送长度
    int sendTotal;//总发送长度
    boolean isFinish;
    byte[] sendData;
    int crcCount;
    List<Integer> list;
    private HashMap<Integer, byte[]> hashMap;
    int maxLength = MainActivity.phoneDataLength;
    private Disposable subscription;
    private Bitmap bitmap;
    private String picString;
    public static final String KEY_PIC_PATH = "KEY_PIC_PATH";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dialog_send_pic);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        ButterKnife.bind(this);
        init();
    }

    private void init() {
        picString = getIntent().getStringExtra(KEY_PIC_PATH);
        subscription = RxBus.getInstance().toObservable(BleData.class).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<BleData>() {
            @Override
            public void accept(BleData data) throws Exception {
                String action = data.getAction();
                if (BleService.ACTION_GATT_onDescriptorWrite.equals(action)) {

                } else if (BleService.ACTION_GATT_DISCONNECTED.equals(action)) {
//
                } else if (BleService.ACTION_DATA_AVAILABLE.equals(action)) {
                    // Log.i(TAG, "accept: " + ResolveData.byte2Hex(data.getValue()));
                    resolveData(data.getValue());
                }
            }
        });
        Glide.with(this).load(R.drawable.send_pic).into(ivSendPic);
        startSendPicData();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        unSubscribe(subscription);
    }

    protected void unSubscribe(Disposable subscription) {
        if (subscription != null && !subscription.isDisposed()) {
            subscription.dispose();
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            return false;
        }
        return super.onKeyDown(keyCode, event);
    }

    /**
     * RGB888颜色值变RGB565
     *
     * @param red
     * @param green
     * @param blue
     * @return
     */
    private short dataFromRGB(byte red, byte green, byte blue) {
        short data = 0;
        char x = (char) (red & 0xf8);
        char x1 = (char) (green >> 5);
        short data1 = (short) ((x + x1) * 256);
        char y = (char) ((green << 3) & 0xe0);
        char y1 = (char) (blue >> 3);
        short data2 = (short) (y + y1);
        data = (short) (data1 + data2);
        return data;
    }

    private void resolveData(byte[] value) {
        switch (value[0]) {
            case cmdCheck:
                if (value[1] == 1) {//查询是否需要升级
                    startData();
                } else if (value[1] == 2) {//升级数据发送完成
                    packageCount = 0;
                    sendTotal = 0;
                    Count = 0;
                    sendTotalPackage = 0;
                    if (value[2] == 0) {//失败
                        //  info = getString(R.string.GPS_Updated_failed);
                    } else if (value[2] == 1) {//成功
                        //   info = getString(R.string.Gps_Update);
                        //isSuccessful=true;
                        setResult(RESULT_OK);
                        finish();
                    }
                } else if (value[1] == 3) {
                    Log.i(TAG, "resolveData: crc检测");
                } else if (value[1] == 0x10) {//超时
                    Log.i(TAG, "resolveData: 超时");
                }
                break;

            case cmdSend:
                if (hashMap == null) return;
                if (value[1] == 1) {
                    isFinish = false;
                    packageCount++;
                    sendData = hashMap.get(packageCount);
                    updateProgress();
                    if (sendData == null) {
                        endUpdateFile();
                    } else {
                        crcCount = ResolveData.CalcCRC16(sendData, sendData.length);
                        startData();
                    }

                } else if (value[1] == 0) {
                    Log.i(TAG, "resolveData: 重发" + packageCount);
                    isFinish = false;
                    sendData = hashMap.get(packageCount);
                    crcCount = ResolveData.CalcCRC16(sendData, sendData.length);
                    sendTotalPackage = sendTotalPackage - sendData.length;
                    startData();
                }
                break;
        }


    }
    private void updateProgress() {
        float send = sendTotalPackage;
        float total = binByte.length;
        float percent = send / total;
        NumberFormat format = NumberFormat.getPercentInstance();
        format.setMaximumFractionDigits(0);
        tvSendPicProgress.setText(format.format(percent));

    }
    int[] crcList;

    private void initByteValue(Bitmap bitmap) {
        // File binFile = new File(ImageUtils.UPDATEPATH);
        //  binByte = readFile(binFile);
        int mBitmapHeight = bitmap.getHeight();
        int mBitmapWidth = bitmap.getWidth();
        binByte = new byte[240 * 204 * 2];
        int count = 0;
        for (int i = 0; i < mBitmapHeight; i++) {
            for (int j = 0; j < mBitmapWidth; j++) {
                int color = bitmap.getPixel(j, i);
                byte r = (byte) Color.red(color);
                byte g = (byte) Color.green(color);
                byte b = (byte) Color.blue(color);
                short color565 = dataFromRGB(r, g, b);
                binByte[count * 2] = (byte) ((color565 >> 8) & 0xff);
                binByte[count * 2 + 1] = (byte) ((color565) & 0xff);
                count++;
            }
        }

        int length = binByte.length % 4096 == 0 ? binByte.length / 4096 : binByte.length / 4096 + 1;
        crcList = new int[length];
        hashMap = new HashMap<>();
        Log.i(TAG, "initByteValue: " + length);
        for (int i = 0; i < length; i++) {
            int valueLength = 4096;
            if (i * 4096 + valueLength >= binByte.length) {
                valueLength = binByte.length - i * 4096;
            }
            byte[] value = new byte[valueLength];
            System.arraycopy(binByte, i * 4096, value, 0, valueLength);
            int crc = ResolveData.CalcCRC16(value, valueLength);
            crcList[i] = crc;
            hashMap.put(i, value);
        }
        sendData = hashMap.get(packageCount);
        crcCount = ResolveData.CalcCRC16(sendData, sendData.length);
        //showProgressView(true);
        checkUpdateFile();
    }


    private void deleteFile() {
        byte[] value = new byte[4];
        value[0] = cmdCheck;
        value[1] = 0x70;
        int crc16 = ResolveData.CalcCRC16(value, 2);
        value[2] = (byte) ((crc16) & 0xff);
        value[3] = (byte) ((crc16 >> 8) & 0xff);
        BleManager.getInstance().writeValue(value);
    }

    private void checkUpdateFile() {
        int length = binByte.length;
        int lengthCrc = crcList.length * 2;
        int crc16 = ResolveData.CalcCRC16(binByte, binByte.length);
        byte[] value = new byte[10 + lengthCrc];//数据块最多16个，此数组长度固定（崩溃报告显示有超出16的）
        value[0] = cmdCheck;
        value[1] = 01;
        value[2] = (byte) ((length) & 0xff);//低位在前
        value[3] = (byte) ((length >> 8) & 0xff);
        value[4] = (byte) ((length >> 16) & 0xff);
        value[5] = (byte) ((length >> 24) & 0xff);
        value[6] = (byte) ((crc16) & 0xff);
        value[7] = (byte) ((crc16 >> 8) & 0xff);
        for (int i = 0; i < crcList.length; i++) {
            value[8 + i * 2] = (byte) ((crcList[i]) & 0xff);
            value[8 + i * 2 + 1] = (byte) ((crcList[i] >> 8) & 0xff);
        }
        int crcValue16 = ResolveData.CalcCRC16(value, value.length - 2);
        value[value.length - 2] = (byte) ((crcValue16) & 0xff);
        value[value.length - 1] = (byte) ((crcValue16 >> 8) & 0xff);
        BleManager.getInstance().writeValue(value);
    }

    private void endUpdateFile() {
        int length = binByte.length;
        int crc16 = ResolveData.CalcCRC16(binByte, binByte.length);
        byte[] value = new byte[10];
        value[0] = cmdCheck;
        value[1] = 02;
        value[2] = (byte) ((length) & 0xff);//低位在前
        value[3] = (byte) ((length >> 8) & 0xff);
        value[4] = (byte) ((length >> 16) & 0xff);
        value[5] = (byte) ((length >> 24) & 0xff);
        value[6] = (byte) ((crc16) & 0xff);
        value[7] = (byte) ((crc16 >> 8) & 0xff);
        int crcValue16 = ResolveData.CalcCRC16(value, value.length - 2);
        value[value.length - 2] = (byte) ((crcValue16) & 0xff);
        value[value.length - 1] = (byte) ((crcValue16 >> 8) & 0xff);
        BleManager.getInstance().writeValue(value);
    }


    private void startData() {
        if (binByte.length == 0 || maxLength == 0 || isFinish) return;
        if (sendData == null) {
            endUpdateFile();
            return;
        }
        int dataLength = sendData.length;
        int contentLength = isFinish ? maxLength - 7 : maxLength - 5;
        isFinish = false;
        if (sendTotal + contentLength >= dataLength) {
            contentLength = dataLength - sendTotal;
            sendTotal = 0;
            isFinish = true;
        } else {
            sendTotal += contentLength;
        }
        if (sendTotalPackage + contentLength >= binByte.length) {
            contentLength = binByte.length - sendTotalPackage;

        }
        int length = isFinish ? contentLength + 7 : contentLength + 5;
        byte[] value = new byte[length];
        value[0] = cmdSend;
        value[1] = (byte) packageCount;
        value[2] = (byte) Count++;
        System.arraycopy(binByte, sendTotalPackage, value, 3, contentLength);
        if (isFinish) {
            value[value.length - 4] = (byte) ((crcCount) & 0xff);
            value[value.length - 3] = (byte) ((crcCount >> 8) & 0xff);
        }
        int crc16 = ResolveData.CalcCRC16(value, value.length - 2);
        value[value.length - 2] = (byte) ((crc16) & 0xff);
        value[value.length - 1] = (byte) ((crc16 >> 8) & 0xff);
        sendTotalPackage += contentLength;
        //Log.i(TAG, "startUpDate: l " + sendTotalPackage);
        BleManager.getInstance().offerValue(value);
        if (isFinish) {
            Count = 0;
            BleManager.getInstance().offerValue((getEnd(packageCount, crcCount)));
            BleManager.getInstance().writeValue();
        } else {
            startData();
        }

    }

    private byte[] getEnd(int count, int crc) {
        byte[] value = new byte[7];
        value[0] = cmdSend;
        value[1] = (byte) count;
        value[2] = (byte) 0xff;
        value[3] = (byte) ((crc) & 0xff);
        value[4] = (byte) ((crc >> 8) & 0xff);
        int crc16 = ResolveData.CalcCRC16(value, value.length - 2);
        value[5] = (byte) ((crc16) & 0xff);
        value[6] = (byte) ((crc16 >> 8) & 0xff);
        return value;
    }

    private void startSendPicData() {
//        File file = new File(ImageUtils.headPath);
//        if (!file.exists()) {
//            file.mkdirs();
//        }
//        final File head = new File(file, "Watch");
        final File head = new File(picString);
        if (!head.exists()) return;
        try {
            Observable.create(new ObservableOnSubscribe<Object>() {
                @Override
                public void subscribe(ObservableEmitter<Object> emitter) throws Exception {

                    bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeFile(head.getAbsolutePath()), 240, 204, true);
                    emitter.onComplete();
                }
            }).compose(SchedulersTransformer.io2MainObservable()).subscribe(new Observer<Object>() {
                @Override
                public void onSubscribe(Disposable d) {

                }

                @Override
                public void onNext(Object o) {

                }

                @Override
                public void onError(Throwable e) {
                    e.printStackTrace();
                }

                @Override
                public void onComplete() {
                    initByteValue(bitmap);
                }
            });


        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}
